package com.baidu.health.WebSocket;

import com.baidu.health.pojo.webVo.OnlineUserInfo;
import com.baidu.health.pojo.webVo.UserRedisMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Set;

/**
 * 客服的websocket服务
 * @author 崔先生
 * @version 1.0.0
 * @date 2022/04/12
 * ckassName java.lang.String
 */

@Slf4j
@Component
@ServerEndpoint(value = "/serviceChat")
public class ServiceWebSocketClient {
    @Autowired
    RedisTemplate<String,Object> redisTemplate;
//    RedisTemplate<String, Object> redisTemplate;

    private Session _session = null;
    private final  String onlineUserKey = "customer_websocket_online_services";
    private final  String onlineAskKey = "customer_websocket_online_users";

    /**
     * 连接时自动调用
     *
     * @param session 会话
     */
    @OnOpen
    public void onOpen(Session session) {
        this._session = session;
        putUserToMap(session);

        log.info("有新连接加入，当前在线数为" + getOnlineUserCount());
    }

    /**
     * 关闭时被回调
     *
     * @param session 会话
     */
    @OnClose
    public void onClose(Session session) {

        removeUserFromMap(session);
        log.info("有一连接关闭！当前在线数为" + getOnlineUserCount());
    }
    /**
     * 收到消息时回调:收到的消息写入数据库，并放到redis：通过MQ异步写入到MySQL
     * 接收到消息，直接把消息发送到MQ队列，由消费者来解析并处理这个消息
     * @param message 消息
     * @param session 会话
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        //--1 判断用户
        OnlineUserInfo user = getUserBySession(session);
        if(user == null) {
            log.error("没有找到用户："+session.getId());
            return;
        }

        //--2 获取到用户的信息：用户ID、用户名称
        // 1|6,貂蝉
        // 2|666,可以的，亲
        String[] cmds = message.split("|");
        if(cmds.length != 2) {
            log.error("消息格式错误："+session.getId());
            return;
        }

        //--3 协议解析
        if(cmds[0].equals("1")) {
            // 发送的是用户信息:  1,周大福
            String[] msgs = cmds[1].split(",");
            if(msgs.length != 2) {
                log.error("消息无效："+cmds[1]);
                return;
            }
            // 保存用户信息
            user.setUserId(Integer.valueOf(msgs[0]));
            user.setUserName(msgs[1]);
            redisTemplate.opsForHash().put(onlineUserKey, session.getId(), user);
        }
        else if(cmds[0].equals("2")) {
            // 发送的是普通消息
            // 用户发的消息
            // 客服发的消息
            // （消息的类型、消息内容）
            // 0, 7天免费退货吗？
            // 6, 可以的，亲
            // 0, 包装损坏了，可以退吗？
            // 6, 那就不可以了呦
            // -> |msg4|msg3|msg2|msg1| ->
            String[] msgs = cmds[1].split(",");
            if(msgs.length != 2) {
                log.error("消息无效："+cmds[1]);
                return;
            }

            String key = "online_msg_" + user.getUserId();

            UserRedisMessage userRedisMessage = new UserRedisMessage();
            userRedisMessage.setId(user.getUserId());   // 设置客服的ID
            userRedisMessage.setMessage(msgs[1]);
            redisTemplate.opsForList().leftPush(key, userRedisMessage);

            // 更新客服和客户的关联
            Set<Object> keys = redisTemplate.opsForHash().keys(onlineAskKey);
            keys.forEach(item -> {
                String sessionId = (String)item;
                OnlineUserInfo askUser = (OnlineUserInfo)redisTemplate.opsForHash().get(onlineAskKey, sessionId);
                if(askUser != null) {
                    askUser.setServiceId(user.getUserId());
                    askUser.setServiceName(user.getUserName());
                    redisTemplate.opsForHash().put(onlineAskKey, sessionId, askUser);
                    return;
                }
            });


            // TODO 发送消息到MQ中，消费者接收消息，存入数据库
        }
        else if(cmds[0].equals("3")) {
            Set<Object> keys = redisTemplate.opsForHash().keys(onlineAskKey);
            keys.forEach(item -> {
                String sessionId = (String)item;
                OnlineUserInfo askUser = (OnlineUserInfo)redisTemplate.opsForHash().get(onlineAskKey, sessionId);
                if(askUser != null) {
                    // 查询新消息
                    String key = "online_msg_" + askUser.getUserId();
                    Long size = redisTemplate.opsForList().size(key);
                    Integer msgIndex = 0;
                    while (size> msgIndex) {
                        String redisMsg = (String)redisTemplate.opsForList().index(key, msgIndex);
                        sendMessage(session, redisMsg);

                        msgIndex ++;
                    }
                }
            });
        }

        log.info("来自客户端 " + " 的消息:" + message);
    }

    /**
     * 发送错误时回调
     * @param session 会话
     * @param error   错误
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("LoginResultWebSocket 发生错误");
        error.printStackTrace();
    }

    /**
     * 发送消息
     * @param session 会话
     * @param message 消息
     */
    public void sendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存在线用户信息
     * @param session 会话
     */
    public void putUserToMap(Session session) {

        OnlineUserInfo onlineUserInfo = new OnlineUserInfo();
        onlineUserInfo.setSession(session);
        redisTemplate.opsForHash().put(onlineUserKey, session.getId(), onlineUserInfo);
    }

    /**
     * 删除用户在线信息
     * @param session 会话
     */
    public void removeUserFromMap(Session session) {
        redisTemplate.opsForHash().delete(onlineUserKey, session.getId());
    }

    /**
     * 获取在线的客户端
     * @return {@link Long}
     */
    public Long getOnlineUserCount() {
        Long size = redisTemplate.opsForHash().size(onlineUserKey);

        return size;
    }

    /**
     * 根据session获取用户的信息
     * @param session 会话
     * @return {@link OnlineUserInfo}
     */
    public OnlineUserInfo getUserBySession(Session session) {
        Boolean exists = redisTemplate.opsForHash().hasKey(onlineUserKey, session.getId());
        if(!exists) {
            log.error("没有找到客服信息："+session.getId());
            return null;
        }

        OnlineUserInfo user = (OnlineUserInfo)redisTemplate.opsForHash().get(onlineUserKey, session.getId());
        return user;
    }
}